#include <g-bios.h>
#include <flash/flash.h>


struct Flash *GuFlashOpen(unsigned int num)
{
	struct Flash *pFlash;

	pFlash = GkFlashGet(num);

	if (pFlash) pFlash->pHookFunc = NULL;

	return pFlash;
}


struct Flash *GuFlashOpenEx(const char *name)
{
	int i;
	struct Flash *pFlash = NULL;

	pFlash = GkFlashGetEx(name);

	if (pFlash) pFlash->pHookFunc = NULL;

	return pFlash;
}


int GuFlashClose(struct Flash *pFlash)
{
	pFlash->pHookFunc = NULL; // to be removed

	return 0;
}


// fixme: ULONG *offset, len
int GuFlashRead(struct Flash *pFlash, BYTE *buf, int *offset, int len) 
{
	long ret;
	ULONG nRetLen;

	ret = pFlash->Read(pFlash, *offset, len, &nRetLen, buf);

	*offset += nRetLen;

	if (ret < 0)
	{
		if (len != nRetLen)
			DPRINT("ERROR: fail to read data! %s()\n", __FUNCTION__);
		else
			DPRINT("ECC ERROR: while reading data! %s()\n", __FUNCTION__);

		return -EFAULT;
	}

	return nRetLen;
}


int GuFlashReadRaw(struct Flash *pFlash, BYTE *buf, int *offset, int len) 
{
	int ret;
	struct OobOpt ops;

	memset(&ops, 0, sizeof(struct OobOpt));
	ops.eOpMode   = FLASH_OOB_RAW;
	ops.pOpDatBuf = buf;
	ops.dwOpLen    = len;

	ret = pFlash->ReadOob(pFlash, *offset, &ops);

	*offset += ops.dwOpRetLen;

	if (ret < 0)
		return ret;

	return ops.dwOpRetLen;
}


long GuFlashWrite(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos)
{
	ULONG nRetlen;
	int ret = 0;


	if (*ppos == pFlash->nChipSize)
		return -ENOSPC;

	if (*ppos + count > pFlash->nChipSize)
		count = pFlash->nChipSize - *ppos;

	if (!count)
		return 0;

	ret = pFlash->Write(pFlash, *ppos, count, &nRetlen, buf);
	*ppos += nRetlen;

	BUG_IF(ret != 0);

	return nRetlen;
}


long GuFlashWriteRaw(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos)
{
	int ret;
	struct OobOpt ops;


	memset(&ops, 0, sizeof(struct OobOpt));
	ops.eOpMode   = FLASH_OOB_RAW;
	ops.dwOpLen    = count;
	ops.pOpDatBuf = (BYTE *)buf;
	ops.dwOpOobLen = pFlash->nOobSize;

	ret = pFlash->WriteOob(pFlash, *ppos, &ops);

	if (ret < 0)
	{
		printf("%s() failed! ret = %d\n", __FUNCTION__, ret);
		return ret;
	}
	else if (ops.dwOpRetLen != ops.dwOpLen)
	{
		BUG();
	}

	*ppos +=  ops.dwOpRetLen;

	return ops.dwOpRetLen;
}


long GuFlashWriteOob(struct Flash *pFlash, const char *buf, ULONG count, ULONG *ppos)
{
	int ret;
	UINT32 nRetLen;
	struct OobOpt ops;

	memset(&ops, 0, sizeof(ops));
	ops.eOpMode    = FLASH_OOB_RAW;
	ops.pOpDatBuf  = NULL;
	ops.dwOpLen    = 0;
	ops.pOpOobBuf  = (char *)buf;
	ops.dwOpOobLen = count;

	ret = pFlash->WriteOob(pFlash, *ppos, &ops);

	nRetLen = ops.dwOpRetLen;

	*ppos += nRetLen;

	return nRetLen;
}


void GuFlashSetHook(struct Flash *pFlash, FLASH_HOOK_FUNC pHookFunc, FLASH_HOOK_PARAM *pParam)
{
	pFlash->pHookFunc  = pHookFunc;
	pFlash->pHookParam = pParam;
}


int GuFlashErase(struct Flash *pFlash, UINT32 nStartAddr, UINT32 nLen, UINT32 dwFlags)
{
	int ret;
	struct FerOpt erase;

	memset(&erase, 0, sizeof(struct FerOpt));
	erase.pFlash      = pFlash;
	erase.dwEraseAddr = nStartAddr;
	erase.dwEraseLen  = nLen;
	ALIGN_UP(erase.dwEraseLen, pFlash->nEraseSize);
	erase.isForJffs2  = !!(dwFlags & EDF_JFFS2);
	erase.isAllowBad  = !!(dwFlags & EDF_ALLOWBB);

	ret = pFlash->Erase(pFlash, &erase);

	if (ret < 0)
		printf("%s() nEccFailedCount!\n", __FUNCTION__);

	return ret;
}

